﻿#include "VulkanScene.h"



void CVulkanScenes::PreProcess(
    const TVector<CPreRenderScene>& InScenes
    ,CVulkanViewportWidget* InViewport)
{
    Scenes.Resize(InScenes.Num());
    for (int i = 0; i < InScenes.Num(); i++)
    {
        Scenes[i].BindData(InScenes[i]);
    }

    //统计描述符
    for (int i = 0; i < Scenes.Num(); i++)
    {
        Scenes[i].PreProcess(InViewport);
    }
}

void CVulkanScenes::RecordCommand(vk::CommandBuffer InCommandBuffer
        ,vk::Extent2D InViewportSize
        ,SSceneParameters& InParameters
        ,const SFrustumPoints& InFrustumPoints
        ,CDefferRenderAttachments* Attachments)
{
    for(int i=0;i<Scenes.Num();++i)
    {
        Scenes[i].RecordCommand(
            InCommandBuffer
            ,InViewportSize
            ,InParameters
            ,InFrustumPoints
            ,Attachments
        );
    }
}

CVulkanScene::CVulkanScene()
{
    SceneParameterBuffer = std::make_shared<CSceneParameterBuffer>();
    // SpotLightPainter=std::make_shared<CVulkanSpotLights>();
    // PointLightPainter=std::make_shared<CVulkanPointLights>();
    // DirectionalLightPainter=std::make_shared<CVulkanDirectionalLights>();
    // MeshInstancePainter=std::make_shared<CVulkanMeshInstances>();
}

void CVulkanScene::BindData(const CPreRenderScene &InData)
{
    Data = InData;
}

void CVulkanScene::PreProcess(CVulkanViewportWidget* InViewport)
{
    SceneParameterBuffer->PrepareSelfRecord();
    SpotLightPainter.PreProcess(Data.SpotLights, InViewport);
    PointLightPainter.PreProcess(Data.PointLights, InViewport);
    DirectionalLightPainter.PreProcess(Data.DirectionalLights, InViewport,this);
    MeshInstancePainter.PreProcess(Data.MeshInstances, InViewport, this);    
}

void CVulkanScene::RecordCommand(
    vk::CommandBuffer InCommandBuffer
    ,vk::Extent2D InViewportSize
    ,SSceneParameters& InParameters
    ,const SFrustumPoints& InFrustumPoints
    ,CDefferRenderAttachments* InAttachments
    )
{
    MeshInstancePainter.CreateDescriptorSet();
    SpotLightPainter.RecordShadowMapCommand(InCommandBuffer,this);
    PointLightPainter.RecordShadowMapCommand(InCommandBuffer,this);
    DirectionalLightPainter.RecordShadowMapCommand(
        InCommandBuffer
        ,this
        ,InFrustumPoints
        , InParameters.CameraNearPlane
        , InParameters.CameraFarPlane
        );
    
    SceneParameterBuffer->UpdateBuffer(InParameters);  
    SceneParameterBuffer->UpdateDescriptorSet();


    //render gbuffer
    //begin deffer render pass
    vk::RenderPassBeginInfo RenderPassBeginInfo = vk::RenderPassBeginInfo()
        .setRenderPass(CVulkanContext::Get()->GetSceneGlobal()->SceneRenderPass)
        .setFramebuffer(InAttachments->FrameBuffer)
        .setRenderArea(vk::Rect2D(vk::Offset2D(0, 0),InViewportSize))
        .setClearValues(InAttachments->ClearValues);
        
    InCommandBuffer.beginRenderPass(RenderPassBeginInfo, vk::SubpassContents::eInline);

    InCommandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, (float)InViewportSize.width, (float)InViewportSize.height, 0.0f, 1.0f));

    InCommandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), InViewportSize));

    //SMatrix4x4 ProjectionViewMatrix = InProjectionMatrix * InViewMatrix;

    
    //延迟渲染第一阶段，绘制所有物体到GBuffer
    GetMeshInstancePainter()->RecordGBuffersDrawCommands(
        InCommandBuffer
        // , ProjectionViewMatrix
        // , InParameters.CameraNearPlane
        // , InParameters.CameraFarPlane
        , SceneParameterBuffer
    );

    // for (auto& MeshInstance : GetMeshInstancePainter()->MeshInstances )
    // {
    //     MeshInstance.RecordGBuffersDrawCommands(
    //         CommandBuffer
    //         // , ProjectionViewMatrix
    //         // , InNear
    //         // , InFar
    //         , SceneParameterBuffer
    //         );
    // }

    //延迟渲染第二阶段，延迟光照
    //goto next subpass
    InCommandBuffer.nextSubpass(vk::SubpassContents::eInline);

   
    SpotLightPainter.RecordDefferShadingCommand(
            InCommandBuffer
            ,this
            ,InParameters
            ,InAttachments
            );

  
    PointLightPainter.RecordDefferShadingCommand(
            InCommandBuffer
            ,this
            ,InParameters
            ,InAttachments
            );

  
    DirectionalLightPainter.RecordDefferShadingCommand(
        InCommandBuffer
        ,this
        ,InParameters
        ,InAttachments
        );
    
    //应用环境光照
    if(Data.AmbientLights!=SColor(0,0,0,0))
    {
        InCommandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, CVulkanContext::Get()->GetSceneGlobal()->AmbientLightDefferShadingPipeline);

        InCommandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics
            , CVulkanContext::Get()->GetSceneGlobal()->AmbientLightDefferShadingPipelineLayout
            , 0
            , { InAttachments->DescriptorSet }
            , {}
        );

        CSceneGlobal::SAmbientLightDefferShadingFragmentPushConstant PushConstant;
        PushConstant.AmbientColorWithIntensity = Data.AmbientLights ;

        //push constants
        InCommandBuffer.pushConstants(
            CVulkanContext::Get()->GetSceneGlobal()->AmbientLightDefferShadingPipelineLayout
            , vk::ShaderStageFlagBits::eFragment
            , 0
            , sizeof(CSceneGlobal::SAmbientLightDefferShadingFragmentPushConstant)
            , &PushConstant
        );

        InCommandBuffer.draw(4, 1, 0, 0);
    }


    //第三阶段，无光照阶段
    InCommandBuffer.nextSubpass(vk::SubpassContents::eInline);
    MeshInstancePainter.RecordUnlitDrawCommands(
        InCommandBuffer
        , SceneParameterBuffer
    );
  

    //第四阶段，透明，有光照
    InCommandBuffer.nextSubpass(vk::SubpassContents::eInline);


    InCommandBuffer.endRenderPass();    
}
